/*
 * Copyright (c) 2018-2999 广州市蓝海创新科技有限公司 All rights reserved.
 *
 * https://www.mall4j.com/
 *
 * 未经允许，不可做商业用途！
 *
 * 版权所有，侵权必究！
 */
package com.yami.shop.service.impl;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yami.shop.bean.enums.TransactionUserType;
import com.yami.shop.bean.model.Order;
import com.yami.shop.bean.param.*;
import com.yami.shop.common.util.Arith;
import com.yami.shop.common.util.DateParam;
import com.yami.shop.common.util.DateUtils;
import com.yami.shop.dao.FlowPageAnalyseUserMapper;
import com.yami.shop.dao.OrderMapper;
import com.yami.shop.dao.UserExtensionMapper;
import com.yami.shop.dao.UserMapper;
import com.yami.shop.service.OrderDataAnalysisService;
import lombok.AllArgsConstructor;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

import java.util.*;

import static java.util.Comparator.comparing;
import static java.util.stream.Collectors.*;

/**
 * @author lgh on 2018/09/15.
 */
@Service
@AllArgsConstructor
public class OrderDataAnalysisServiceImpl extends ServiceImpl<OrderMapper, Order> implements OrderDataAnalysisService {

    private final OrderMapper orderMapper;

    private final UserMapper userMapper;

    private final UserExtensionMapper userExtensionMapper;

    private final FlowPageAnalyseUserMapper flowPageAnalyseUserMapper;

    @Override
    public List<CustomerRFMRespTableParam> countPayNumRfm2(CustomerRFMReqParam param) {

        Date recentTime = param.getRecentTime();
        Date mouth = DateUtils.dateToFast(DateUtils.getBeforeDay(recentTime, -30));
        Date threeMouth = DateUtils.dateToFast(DateUtils.getBeforeDay(recentTime, -90));
        Date halfYear = DateUtils.dateToFast(DateUtils.getBeforeDay(recentTime, -180));
        Date year = DateUtils.dateToFast(DateUtils.getBeforeDay(recentTime, -365));
        return orderMapper.getUserOrderCrateTime(param.getType(),recentTime,mouth,threeMouth,halfYear,year);
    }

    @Override
    public UserManagerParam getConsumeData(UserManagerParam param) {
        String userId = param.getUserId();
        // 最近消费时间, 下单支付的时间(积分支付/余额支付), 充值时间， 比较获取最新时间
        Date date = orderMapper.getLastConsumeDateByUserId(param.getUserId());
        param.setReConsTime(date);
        // 消费金额, 累计消费了多少金额：除了积分支付的订单累计金额
        Double amount = orderMapper.countConsumeAmount(userId, 1);
        param.setConsAmount(Objects.nonNull(amount)?amount:0.0);
        // 实付金额, 累计支付的金额: 除了余额支付/积分支付的订单累计金额 + 余额充值金额
        param.setActualAmount(orderMapper.countConsumeAmount(userId, 0));
        // 消费次数, 累计消费的次数（积分下单不包含），下单的次数
        param.setConsTimes(orderMapper.countPayNumByUserId(userId));
        // 平均折扣, 消费下单的优惠总金额/消费次数
        // 优惠总金额
        Double reduceAmount = orderMapper.countReduceAmountByUserId(userId);
        param.setAverDiscount(divAverage(reduceAmount,param.getConsTimes(),2));
        return param;
    }

    @Override
    @Cacheable(cacheNames = "tradeRetained", key = "#param.retainType +':'+ #param.dateType" )
    public List<CustomerRetainRespParam> getTradeRetained(CustomerRetainedReqParam param) {
        return orderMapper.getTradeRetained(param);
    }

    @Override
    @CacheEvict(cacheNames = "tradeRetained", key = "#param.retainType +':'+ #param.dateType")
    public void removeCacheTradeRetained(CustomerRetainedReqParam param) {
    }

    private CustomerRFMRespTableParam countcPayNumRfmParam(CustomerRFMRespTableParam param) {
        int buyers = 0;
        buyers = param.getPayBuyers1()+param.getPayBuyers2()+param.getPayBuyers3()+param.getPayBuyers4()+param.getPayBuyers5();
        param.setPayBuyersTotal(buyers);
        double payTotal = 0.0;
        payTotal = Arith.add(payTotal,param.getPayAmount1());
        payTotal = Arith.add(payTotal,param.getPayAmount2());
        payTotal = Arith.add(payTotal,param.getPayAmount3());
        payTotal = Arith.add(payTotal,param.getPayAmount4());
        payTotal = Arith.add(payTotal,param.getPayAmount5());
        param.setPayAmountTotal(Arith.roundByBanker(payTotal,2));
        param.setPriceSingle1(divAverage(param.getPayAmount1(),param.getPayBuyers1(),2));
        param.setPriceSingle2(divAverage(param.getPayAmount2(),param.getPayBuyers2(),2));
        param.setPriceSingle3(divAverage(param.getPayAmount3(),param.getPayBuyers3(),2));
        param.setPriceSingle4(divAverage(param.getPayAmount4(),param.getPayBuyers4(),2));
        param.setPriceSingle5(divAverage(param.getPayAmount5(),param.getPayBuyers5(),2));
        double priceSingleTotal = 0.0;
        priceSingleTotal = Arith.add(priceSingleTotal,param.getPriceSingle1());
        priceSingleTotal = Arith.add(priceSingleTotal,param.getPriceSingle2());
        priceSingleTotal = Arith.add(priceSingleTotal,param.getPriceSingle3());
        priceSingleTotal = Arith.add(priceSingleTotal,param.getPriceSingle4());
        priceSingleTotal = Arith.add(priceSingleTotal,param.getPriceSingle5());
        param.setPriceSingleTotal(Arith.roundByBanker(priceSingleTotal,2));
        return param;
    }

    @Override
    public CustomerRespParam countPayNum(CustomerReqParam param) {
        CustomerRespParam res = new CustomerRespParam();
        param.setDateTime(null);
        res.setPayNum(orderMapper.countPayCustomerNum(param));
        // 开始时间和结束时间的时间差n天，开始时间的前n天
        getPreDateByRangeTime(param);
        res.setPrePayNum(orderMapper.countPayCustomerNum(param));
        res.setPayNumRate(divAverage(res.getPayNum() - res.getPrePayNum(), res.getPayNum(), 4));
        return res;
    }

    /**
     * 开始时间和结束时间的时间差n天
     * 结束时间是开始时间，开始时间的前n天作为开始时间
     * @param param 时间参数
     */
    private void getPreDateByRangeTime(CustomerReqParam param) {
        Date startTime = param.getStartTime();
        Date endTime = param.getEndTime();
        long days = DateUtil.between(startTime, endTime, DateUnit.DAY);
        DateTime dateTime = DateUtil.offsetDay(startTime, -(int) days);
        param.setStartTime(DateUtil.beginOfDay(dateTime));
        param.setEndTime(DateUtil.endOfDay(startTime));
    }

    @Override
    public List<CustomerPayParam> countCustomerParam(CustomerReqParam param, Map<Date, Integer> levelMap) {
        List<DateParam> everyDays = DateUtils.findEveryDays(param.getStartTime(), param.getEndTime());
        List<CustomerPayParam> flowParams = flowPageAnalyseUserMapper.countByTime(param.getStartTime(),param.getEndTime());
        List<CustomerPayParam> userParams = userMapper.countUserByMemberParam(param.getStartTime(),param.getEndTime(),1);
        List<CustomerPayParam> orderParams = orderMapper.countPayCustomerNumByTime(param.getStartTime(),param.getEndTime());
        Map<Date, Integer> flowMap = flowParams.stream().collect(toMap(CustomerPayParam::getCreateDate, CustomerPayParam::getNumber));
        Map<Date, Integer> userMap = userParams.stream().collect(toMap(CustomerPayParam::getCreateDate, CustomerPayParam::getNumber));
        Map<Date, Integer> orderMap = orderParams.stream().collect(toMap(CustomerPayParam::getCreateDate, CustomerPayParam::getNumber));
        List<CustomerPayParam> res = new ArrayList<>();
        for (DateParam everyDay : everyDays) {
            CustomerPayParam respParam = new CustomerPayParam();
            param.setStartTime(everyDay.getStartTime());
            param.setEndTime(everyDay.getEndTime());
            param.setDateTime(null);
            respParam.setCurrentDay(DateUtils.dateToStrYmd(everyDay.getStartTime()));
            respParam.setVisitor(flowMap.getOrDefault(everyDay.getStartTime(),0));
            respParam.setPayNum(orderMap.getOrDefault(everyDay.getStartTime(),0));
            if (levelMap.containsKey(everyDay.getStartTime())) {
                respParam.setFashNum(levelMap.get(everyDay.getStartTime()));
            } else {
                respParam.setFashNum(0);
            }
//            // 访客数
//            respParam.setVisitor(flowPageAnalyseUserMapper.countAllVisitor(null,param.getStartTime(),param.getEndTime()));
//            // 累积会员数, 页面重复统计，这里不统计
////            respParam.setMember(userMapper.countMemberByParam(param))
//            // 成交客户数（每天成交的用户数，不等于一段时间内成交的客户数，因为成交客户可能是重复的）
//            respParam.setPayNum(orderMapper.countPayCustomerNum(param));
//            // 累积粉丝数/付费会员数
//            param.setMember(1);
//            respParam.setFashNum(userMapper.countUserByParam(param));
            res.add(respParam);
        }
        return res;
    }

    @Override
    public Integer countMemberPayNum(CustomerReqParam param) {
        return orderMapper.countMemberPayNum(param);
    }

    @Override
    public CustomerDealRespParam getCustomerDeal(CustomerReqParam param) {
        CustomerDealRespParam res = new CustomerDealRespParam();
        CustomerDealParam allDeal = new CustomerDealParam();
        CustomerDealParam newDeal = new CustomerDealParam();
        CustomerDealParam oldDeal = new CustomerDealParam();
        Date startTime = param.getStartTime();
        Date endTime = param.getEndTime();
        param.setDateTime(null);
        // 客户数
        allDeal.setCustomerNum(orderMapper.countMemberPayNum(param));
        Date beforeYear = DateUtils.getBeforeYear(startTime, -2);
        newDeal.setCustomerNum(orderMapper.countNewMemberPayNum(beforeYear, startTime, endTime));
        oldDeal.setCustomerNum(orderMapper.countOldMemberPayNum(beforeYear, startTime, endTime));
        // 付款金额
        allDeal.setPayAmount(getDouble(orderMapper.countMemberPayAmount(param)));
        newDeal.setPayAmount(getDouble(orderMapper.countNewMemberPayAmount(beforeYear, startTime, endTime)));
        oldDeal.setPayAmount(getDouble(orderMapper.countOldMemberPayAmount(beforeYear, startTime, endTime)));
        // 客户数占比
        param.setStartTime(null);
        param.setEndTime(null);
        Integer allUsers = userMapper.countUserByParam(param);
        allDeal.setCustomerRate(divAverage(allDeal.getCustomerNum(), allUsers, 4));
        newDeal.setCustomerRate(divAverage(newDeal.getCustomerNum(), allDeal.getCustomerNum(), 4));
        oldDeal.setCustomerRate(divAverage(oldDeal.getCustomerNum(), allDeal.getCustomerNum(), 4));
        // 客单价
        allDeal.setCustomerSinglePrice(divAverage(allDeal.getPayAmount(), allDeal.getCustomerNum(), 4));
        newDeal.setCustomerSinglePrice(divAverage(newDeal.getPayAmount(), newDeal.getCustomerNum(), 4));
        oldDeal.setCustomerSinglePrice(divAverage(oldDeal.getPayAmount(), oldDeal.getCustomerNum(), 4));
        // 访问-付款转化率
        // 两年的总访客数
        Integer totalVisitor = flowPageAnalyseUserMapper.countVisitorNumByDate(beforeYear,endTime);
        // 支付访客数
        Integer payVisitor = flowPageAnalyseUserMapper.countPaidVisitorNumByDate(beforeYear,endTime);
        // 未支付访客数 = 两年的总访客数 - 支付访客数
        allDeal.setTransRate(divAverage(allDeal.getCustomerNum(),totalVisitor,4));
        newDeal.setTransRate(divAverage(newDeal.getCustomerNum(),totalVisitor-payVisitor,4));
        oldDeal.setTransRate(divAverage(oldDeal.getCustomerNum(),payVisitor,4));
        res.setAllDeal(allDeal);
        res.setNewDeal(newDeal);
        res.setOldDeal(oldDeal);
        List<CustomerDealTrendParam> listDeal = new ArrayList<>();
        List<DateParam> everyDays = DateUtils.findEveryDays(startTime, endTime);
        for (DateParam everyDay : everyDays) {
            CustomerDealTrendParam trend = new CustomerDealTrendParam();
            Date startTime1 = everyDay.getStartTime();
            Date endTime1 = everyDay.getEndTime();
            trend.setCurrentDay(DateUtils.dateToStrYmd(everyDay.getEndTime()));
            trend.setNewCustomerNum(orderMapper.countNewMemberPayNum(beforeYear, startTime1, endTime1));
            trend.setOldCustomerNum(orderMapper.countOldMemberPayNum(beforeYear, startTime1, endTime1));
            trend.setNewPayAmount(getDouble(orderMapper.countNewMemberPayAmount(beforeYear, startTime1, endTime1)));
            trend.setOldPayAmount(getDouble(orderMapper.countOldMemberPayAmount(beforeYear, startTime1, endTime1)));
            trend.setNewCustomerSinglePrice(divAverage(trend.getNewPayAmount(), trend.getNewCustomerNum(), 4));
            trend.setOldCustomerSinglePrice(divAverage(trend.getOldPayAmount(), trend.getOldCustomerNum(), 4));
            trend.setNewTransRate(divAverage(trend.getNewCustomerNum(),totalVisitor-payVisitor,4));
            trend.setOldTransRate(divAverage(trend.getOldCustomerNum(),payVisitor,4));
            listDeal.add(trend);
        }
        res.setListDeal(listDeal);
        return res;
    }

    @Override
    public List<CustomerRFMRespParam> countPayNumRfm(CustomerRFMReqParam param) {
        List<CustomerRFMRespParam> list = new ArrayList<>();
        Integer type = param.getType();
        Date recentTime = param.getRecentTime();
        // 1 2 3 4 f=5 表示f>=5
        Integer f = 1;
        // R<=30
        Date startTime = new Date();
        Date endTime = recentTime;
        for (int i = 1; i < 6; i++) {
            CustomerRFMRespParam param1 = new CustomerRFMRespParam();
            param1.setRecency(1);
            param1.setFrequency(i);
            startTime = DateUtils.dateToFast(DateUtils.getBeforeDay(recentTime, -30));
            endTime = recentTime;
            param1.setPayBuyers(orderMapper.countPayNumRfm(1, i, startTime, endTime));
            param1.setPayAmount(getDouble(orderMapper.sumPayAmountRfm(1, i, startTime, endTime)));
            list.add(param1);
        }
        // 30<R<=90
        for (int i = 1; i < 6; i++) {
            CustomerRFMRespParam param2 = new CustomerRFMRespParam();
            param2.setRecency(2);
            param2.setFrequency(i);
            startTime = DateUtils.dateToFast(DateUtils.getBeforeDay(recentTime, -90));
            endTime = DateUtils.dateToFast(DateUtils.getBeforeDay(recentTime, -30));
            param2.setPayBuyers(orderMapper.countPayNumRfm(1, i, startTime, endTime));
            param2.setPayAmount(getDouble(orderMapper.sumPayAmountRfm(1, i, startTime, endTime)));
            list.add(param2);
        }
        // 90<R<=180
        for (int i = 1; i < 6; i++) {
            CustomerRFMRespParam param3 = new CustomerRFMRespParam();
            param3.setRecency(3);
            param3.setFrequency(i);
            startTime = DateUtils.dateToFast(DateUtils.getBeforeDay(recentTime, -180));
            endTime = DateUtils.dateToFast(DateUtils.getBeforeDay(recentTime, -90));
            param3.setPayBuyers(orderMapper.countPayNumRfm(1, i, startTime, endTime));
            param3.setPayAmount(getDouble(orderMapper.sumPayAmountRfm(1, i, startTime, endTime)));
            list.add(param3);
        }
        // 180<R<=365
        for (int i = 1; i < 6; i++) {
            CustomerRFMRespParam param4 = new CustomerRFMRespParam();
            param4.setRecency(4);
            param4.setFrequency(i);
            startTime = DateUtils.dateToFast(DateUtils.getBeforeDay(recentTime, -365));
            endTime = DateUtils.dateToFast(DateUtils.getBeforeDay(recentTime, -180));
            param4.setPayBuyers(orderMapper.countPayNumRfm(1, i, startTime, endTime));
            param4.setPayAmount(getDouble(orderMapper.sumPayAmountRfm(1, i, startTime, endTime)));
            list.add(param4);
        }
        // R > 365
        for (int i = 1; i < 6; i++) {
            CustomerRFMRespParam param4 = new CustomerRFMRespParam();
            param4.setRecency(5);
            param4.setFrequency(i);
            Integer payBuyers = 0;
            Double amount = 0.0;
            if (Objects.equals(0, type)) {
                startTime = DateUtils.dateToFast(DateUtils.getBeforeDay(recentTime, -365));
                payBuyers = orderMapper.countPayNumRfm(0, i, startTime, null);
                amount = getDouble(orderMapper.sumPayAmountRfm(0, i, startTime, null));
            }
            param4.setPayBuyers(payBuyers);
            param4.setPayAmount(amount);
            list.add(param4);
        }
        return list;
    }

    @Override
    public List<Order> getOrderAndOrderItemByOrderNumberList(Set<String> orderNumberList) {
        return orderMapper.getOrderAndOrderItemByOrderNumberList(orderNumberList);
    }

    @Override
    public CustomerConsumeRespParam getConsumePower(CustomerConsumeReqParam param) {
        CustomerConsumeRespParam respParam = null;
        Date startTime = DateUtil.beginOfDay(param.getStartTime());
        Date endTime = DateUtil.endOfDay(param.getEndTime());
//        Date beforeYear = DateUtils.getBeforeYear(startTime, -2);
        // 0全部成交客户 1新成交客户 2老成交客户
        Integer type = param.getType();
        // 获取新用户信息
        if (!Objects.equals(TransactionUserType.OLD_TRANSACTIONUSERTYPE.value(), type)) {
            respParam = orderMapper.getConsumePowerUserInfo(TransactionUserType.NEW_TRANSACTION_USE.value(), startTime, endTime);
        }
        if(Objects.isNull(respParam)) {
            respParam = new CustomerConsumeRespParam();
        }
        respParam.setStart(0.0D);
        // 如果是获取新用户信息，此处已查询完成，不需要再执行后面的步骤
        if (Objects.equals(TransactionUserType.NEW_TRANSACTION_USE.value(), type)) {
            respParam.setEnd(Math.ceil(respParam.getNewPayAmount()));
            return respParam;
        }
        // 获取旧用户信息
        if (!Objects.equals(TransactionUserType.NEW_TRANSACTION_USE.value(), type)) {
            CustomerConsumeRespParam oldRespParam = orderMapper.getConsumePowerUserInfo(TransactionUserType.OLD_TRANSACTIONUSERTYPE.value(), startTime, endTime);
            respParam.setOldPayBuyers(oldRespParam.getOldPayBuyers());
            respParam.setOldPayAmount(oldRespParam.getOldPayAmount());
            respParam.setOldPayProdCount(oldRespParam.getOldPayProdCount());
        }
        // 如果是获取旧用户信息，此处已查询完成，不需要再执行后面的步骤
        if (Objects.equals(TransactionUserType.OLD_TRANSACTIONUSERTYPE.value(), type)) {
            respParam.setEnd(Math.ceil(respParam.getOldPayAmount()));
            return respParam;
        }

        // 查询全部用户时
        respParam.setEnd(Math.ceil(Arith.add(respParam.getNewPayAmount(), respParam.getOldPayAmount())));
        if (respParam.getEnd() <= 50) {
            respParam.setEnd(50.0);
        }
        return respParam;
    }

    @Override
    public CustomerConsumeRespParam getConsumeFrequency(CustomerConsumeReqParam param) {
        CustomerConsumeRespParam respParam = new CustomerConsumeRespParam();
        Integer type = param.getType();
        // 0全部成交客户 1新成交客户 2老成交客户
        Date startTime = DateUtil.beginOfDay(param.getStartTime());
        Date endTime = DateUtil.endOfDay(param.getEndTime());
        Date beforeYear = DateUtils.getBeforeYear(startTime, -2);
        if (!Objects.equals(TransactionUserType.OLD_TRANSACTIONUSERTYPE.value(), type)) {
            respParam.setNewPayAmount(getDouble(orderMapper.countNewMemberPayAmount(beforeYear, startTime, endTime)));
            respParam.setNewPayBuyers(orderMapper.countNewMemberPayNum(beforeYear, startTime, endTime));
            respParam.setNewPayProdCount(getInteger(orderMapper.countNewOrOldPayProdNum(0, beforeYear, startTime, endTime)));
        }
        Integer newPayTimes = orderMapper.countNewOrOldPayTimes(0, beforeYear, startTime, endTime);
        if (Objects.equals(1, type)) {
            respParam.setEnd(Double.valueOf(newPayTimes));
            return respParam;
        }
        respParam.setOldPayAmount(getDouble(orderMapper.countOldMemberPayAmount(beforeYear, startTime, endTime)));
        respParam.setOldPayBuyers(orderMapper.countOldMemberPayNum(beforeYear, startTime, endTime));
        respParam.setOldPayProdCount(getInteger(orderMapper.countNewOrOldPayProdNum(1, beforeYear, startTime, endTime)));
        Integer oldPayTimes = orderMapper.countNewOrOldPayTimes(1, beforeYear, startTime, endTime);
        if (Objects.equals(TransactionUserType.OLD_TRANSACTIONUSERTYPE.value(), type)) {
            respParam.setEnd(Double.valueOf(oldPayTimes));
            return respParam;
        }
        respParam.setEnd(Double.valueOf(newPayTimes + oldPayTimes));
        return respParam;
    }

    @Override
    public CustomerRepurchaseRespParam getConsumeRepurchaseCount(CustomerConsumeReqParam param) {
        Integer type = param.getType();
        // 0全部成交客户 1新成交客户 2老成交客户
        Date endTime = DateUtil.endOfDay(param.getEndTime());
        Date startTime = DateUtil.beginOfDay(param.getStartTime());
        Date beforeYear = DateUtils.getBeforeYear(startTime, -2);
        Integer cycle = -param.getCycle();
        Integer payBuyers = 0;
        Double payAmount = 0.0;
        Integer payProdCount = 0;
        Integer repurchaseCount = 0;
        CustomerRepurchaseRespParam respParam = new CustomerRepurchaseRespParam();
        List<CustomerRepurchaseDetailParam> res = new ArrayList<>();
        CustomerRepurchaseDetailParam deParam = new CustomerRepurchaseDetailParam();
        if (!Objects.equals(TransactionUserType.OLD_TRANSACTIONUSERTYPE.value(), type)) {
            // 全部/新客户
            List<CustomerOrderParam> orderParams = orderMapper.getNewRepurchaseParam(param.getShopId(), 0, beforeYear, startTime, endTime);
            ArrayList<CustomerOrderParam> collect = orderParams.stream().collect(collectingAndThen(toCollection(() -> new TreeSet<>(comparing(CustomerOrderParam::getUserId))), ArrayList::new));
            payBuyers = payBuyers + collect.size();
            for (CustomerOrderParam orderParam : collect) {
                CustomerRepurchaseDetailParam detailParam = orderMapper.getNewRepurchaseCount(param.getShopId(), 0, cycle, orderParam.getUserId(), orderParam.getPayTime(), beforeYear, startTime, endTime);
                payAmount = Arith.add(payAmount, getDouble(detailParam.getPayAmount()));
                payProdCount = payProdCount + detailParam.getPayProdCount();
                repurchaseCount = repurchaseCount + detailParam.getRepurchaseCount();
            }
        }
        if (!Objects.equals(TransactionUserType.NEW_TRANSACTION_USE.value(), type)) {
            // 全部/老客户
            List<CustomerOrderParam> orderParams = orderMapper.getNewRepurchaseParam(param.getShopId(), 1, beforeYear, startTime, endTime);
            ArrayList<CustomerOrderParam> collect = orderParams.stream().collect(collectingAndThen(toCollection(() -> new TreeSet<>(comparing(CustomerOrderParam::getUserId))), ArrayList::new));
            payBuyers = payBuyers + collect.size();
            for (CustomerOrderParam orderParam : collect) {
                CustomerRepurchaseDetailParam detailParam = orderMapper.getNewRepurchaseCount(param.getShopId(), 1, cycle, orderParam.getUserId(), orderParam.getPayTime(), beforeYear, startTime, endTime);
                payAmount = Arith.add(payAmount, getDouble(detailParam.getPayAmount()));
                payProdCount = payProdCount + detailParam.getPayProdCount();
                repurchaseCount = repurchaseCount + detailParam.getRepurchaseCount();
            }
        }
        deParam.setPayAmount(payAmount);
        deParam.setPayBuyers(payBuyers);
        deParam.setPayProdCount(payProdCount);
        deParam.setRepurchaseCount(repurchaseCount);
        res.add(deParam);
        respParam.setDetail(res);
        return respParam;
    }

    @Override
    public MemberContributeRespParam getMemberContributeValue(MemberReqParam param) {
        Date startTime = param.getStartTime();
        Date endTime = param.getEndTime();
        MemberContributeRespParam respParam = new MemberContributeRespParam();
        // 普通会员
        MemberContributeValueParam publicMember = new MemberContributeValueParam();
        // 付费会员
        MemberContributeValueParam paidMember = new MemberContributeValueParam();

        // 普通会员
        param.setDateTime(endTime);
        param.setMemberType(1);
        publicMember.setTotalMember(userExtensionMapper.countMemberByParam(param));
        param.setDateTime(null);
        publicMember.setPayMemberNum(orderMapper.countPaidMemberByParam(param,null));
        // TODO 支付频次暂不统计 时间段内：支付订单数 / 消费人数
        publicMember.setPayOrderNum(orderMapper.countPaidMemberByParam(param,1));
        publicMember.setFrequencyOfConsume(divAverage(publicMember.getPayOrderNum(),publicMember.getPayMemberNum(),2));
        publicMember.setPayAmount(getDouble(orderMapper.countMemberPaidAmount(param)));
        publicMember.setPricePerMember(divAverage(publicMember.getPayAmount(),publicMember.getPayMemberNum(),4));
        // 付费会员
        param.setMemberType(2);
        param.setDateTime(endTime);
        paidMember.setTotalMember(userExtensionMapper.countMemberByParam(param));
        param.setDateTime(null);
        paidMember.setPayMemberNum(orderMapper.countPaidMemberByParam(param,null));
        paidMember.setPayAmount(getDouble(orderMapper.countMemberPaidAmount(param)));
        paidMember.setPayOrderNum(orderMapper.countPaidMemberByParam(param,1));
        paidMember.setFrequencyOfConsume(divAverage(paidMember.getPayOrderNum(),paidMember.getPayMemberNum(),2));
        paidMember.setPricePerMember(divAverage(paidMember.getPayAmount(),paidMember.getPayMemberNum(),4));
        publicMember.setTotalMemberRate(divAverage(publicMember.getTotalMember(),publicMember.getTotalMember()+paidMember.getTotalMember(),4));
        paidMember.setTotalMemberRate(Arith.sub(1,publicMember.getTotalMemberRate()));
        publicMember.setPayMemberNumRate(divAverage(publicMember.getPayMemberNum(),publicMember.getPayMemberNum()+ paidMember.getPayMemberNum(),4));
        paidMember.setPayMemberNumRate(Arith.sub(1,publicMember.getPayMemberNumRate()));
        publicMember.setPayAmountRate(divAverage(publicMember.getPayAmount(),Arith.add(publicMember.getPayAmount(),paidMember.getPayAmount()),4));
        paidMember.setPayAmountRate(Arith.sub(1,publicMember.getPayAmountRate()));

        respParam.setPublicMember(publicMember);
        respParam.setPaidMember(paidMember);
        return respParam;
    }

    @Override
    public MemberDealRespParam getMemberDeal(MemberReqParam param) {
        MemberDealRespParam respParam = new MemberDealRespParam();
        MemberDealParam allMember = new MemberDealParam();
        MemberDealParam newMember = new MemberDealParam();
        MemberDealParam oldMember = new MemberDealParam();
        List<MemberDealTreadParam> trend = new ArrayList<>();
        Date startTime = param.getStartTime();
        Date endTime = param.getEndTime();
        param.setDateTime(null);
        // 客户数
        allMember.setPayMemberNum(orderMapper.countMemberPayNum(param));
        Date beforeYear = DateUtils.getBeforeYear(startTime, -2);
        newMember.setPayMemberNum(orderMapper.countNewMemberPayNum(beforeYear, startTime, endTime));
        oldMember.setPayMemberNum(orderMapper.countOldMemberPayNum(beforeYear, startTime, endTime));
        // 成交会员占比
        Integer payMemberNum = allMember.getPayMemberNum();
        allMember.setPayMemberNumRate(1.0);
        newMember.setPayMemberNumRate(divAverage(newMember.getPayMemberNum(),payMemberNum,4));
        oldMember.setPayMemberNumRate(divAverage(oldMember.getPayMemberNum(),payMemberNum,4));
        // 付款金额
        allMember.setPayAmount(getDouble(orderMapper.countMemberPayAmount(param)));
        newMember.setPayAmount(getDouble(orderMapper.countNewMemberPayAmount(beforeYear, startTime, endTime)));
        oldMember.setPayAmount(getDouble(orderMapper.countOldMemberPayAmount(beforeYear, startTime, endTime)));
        // 支付金额占比
        allMember.setPayAmountRate(1.0);
        newMember.setPayAmountRate(divAverage(newMember.getPayAmount(),allMember.getPayAmount(),4));
        oldMember.setPayAmountRate(Arith.sub(allMember.getPayAmountRate(),newMember.getPayAmountRate()));
        // 客单价
        allMember.setPricePerMember(divAverage(allMember.getPayAmount(),allMember.getPayMemberNum(),2));
        newMember.setPricePerMember(divAverage(newMember.getPayAmount(),newMember.getPayMemberNum(),2));
        oldMember.setPricePerMember(divAverage(oldMember.getPayAmount(),oldMember.getPayMemberNum(),2));
        // 支付订单数
        newMember.setPayOrderNum(orderMapper.countNewOrOldMemberPayOrder(0,beforeYear, startTime, endTime));
        oldMember.setPayOrderNum(orderMapper.countNewOrOldMemberPayOrder(1,beforeYear, startTime, endTime));
        allMember.setPayOrderNum(newMember.getPayOrderNum() + oldMember.getPayOrderNum());
        respParam.setAllMember(allMember);
        respParam.setNewMember(newMember);
        respParam.setOldMember(oldMember);
        List<DateParam> everyDays = DateUtils.findEveryDays(startTime, endTime);
        for (DateParam everyDay : everyDays) {
            MemberDealTreadParam res = new MemberDealTreadParam();
            Date dayStartTime = everyDay.getStartTime();
            Date dayEndTime = everyDay.getEndTime();
            res.setCurrentDay(DateUtils.dateToNumber(dayStartTime));
            res.setNewPayMemberNum(orderMapper.countNewMemberEveryDayPayNum(0,beforeYear, startTime,dayStartTime, dayEndTime));
            res.setOldPayMemberNum(orderMapper.countNewMemberEveryDayPayNum(1,beforeYear, startTime,dayStartTime, dayEndTime));
            res.setNewPayOrderNum(orderMapper.countNewOrOldMemberEveryDayPayPayOrder(0,beforeYear, startTime,dayStartTime, dayEndTime));
            res.setOldPayOrderNum(orderMapper.countNewOrOldMemberEveryDayPayPayOrder(1,beforeYear, startTime,dayStartTime, dayEndTime));
            res.setNewPayAmount(getDouble(orderMapper.countNewMemberEveryDayPayAmount(0,beforeYear, startTime,dayStartTime, dayEndTime)));
            res.setOldPayAmount(getDouble(orderMapper.countNewMemberEveryDayPayAmount(1,beforeYear, startTime,dayStartTime, dayEndTime)));
            res.setNewPricePerMember(divAverage(res.getNewPayAmount(),res.getNewPayMemberNum(),2));
            res.setOldpricePerMember(divAverage(res.getOldPayAmount(),res.getOldPayMemberNum(),2));
            trend.add(res);
        }
        respParam.setTrendParam(trend);
        return respParam;
    }


    private Double getDouble(Double value) {
        if (Objects.isNull(value)) {
            return 0.0;
        }
        return value;
    }

    private Integer getInteger(Integer value) {
        if (Objects.isNull(value)) {
            return 0;
        }
        return value;
    }

    private Double divAverage(Integer a, Integer b, Integer scale) {
        if (Objects.isNull(b) || b == 0 || Objects.isNull(a)) {
            return 0.0;
        }
        return Arith.div(a, b, scale);
    }

    private Double divAverage(Double a, Integer b, Integer scale) {
        if (Objects.isNull(b) || b == 0 || Objects.isNull(a)) {
            return 0.0;
        }
        return Arith.div(a, b, scale);
    }
    private Double divAverage(Double a, Double b, Integer scale) {
        if (Objects.isNull(b) || b == 0 || Objects.isNull(a)) {
            return 0.0;
        }
        return Arith.div(a, b, scale);
    }


}
